package com.hmall.order.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.easysdk.factory.Factory;
import com.google.common.collect.Maps;
import com.hmall.order.config.AliPayConfig;
import com.hmall.order.mapper.OrderMapper;
import com.hmall.order.pojo.Order;
import com.hmall.order.pojo.OrderDetail;
import com.hmall.order.service.WxAndZfbPayService;
import com.hmall.utils.WXPayUtil;
import com.hmall.winxin.WXConstants;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mengjie
 */
@Slf4j
@Service
public class WxAndZfbPayServiceImpl implements WxAndZfbPayService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private AliPayConfig aliPayConfig;

    private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
    private static final String FORMAT = "JSON";
    private static final String CHARSET = "utf-8";
    private static final String SIGN_TYPE = "RSA2";

    /**
     * 微信支付
     *
     * @param type
     * @param orderId
     * @return
     */
    @Override
    @SneakyThrows
    public String wxPay(Integer type, Long orderId) {
        //根据订单号查询订单信息
        OrderDetail orderDetail = orderMapper.selectOrderDetailById(orderId);
        log.info("订单信息：{}", orderDetail);
        //以map集合的形式，封装微信支付的请求参数
        Map<String, String> map = Maps.newHashMap();
        map.put("appid", WXConstants.APP_ID); //公众账号ID
        map.put("mch_id", WXConstants.MCH_ID);//商户号
        map.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
        map.put("body", orderDetail.getName());//商品描述
        map.put("out_trade_no", String.valueOf(orderId));//商户订单号
        map.put("total_fee", "1");//标价金额
        map.put("spbill_create_ip", "127.0.0.1");//终端IP
        map.put("notify_url", WXConstants.NOTIFY_URL);//通知地址
        map.put("trade_type", "NATIVE");//Native支付
        //将map集合转成xml格式，并且生成参数的签名
        String xml = WXPayUtil.generateSignedXml(map);

        //和微信支付对接，获取支付二维码地址
        HttpResponse response = HttpUtil.createPost(WXConstants.API_URL) //POST请求
                .body(xml) //请求体的数据
                .header("Content-Type", "application/xml")//请求体：表述的是请求体的数据格式为xml类型
                .execute();//发送请求

        String xmlBody = response.body(); //xml

        //将xml格式转为map集合
        map = WXPayUtil.xmlToMap(xmlBody);

        //判断微信返回的数据是否是SUCCESS
        if (StrUtil.endWithIgnoreCase("SUCCESS", map.get("return_code"))) {
            //响应正常
            return map.get("code_url");
        } else {
            //有异常
            throw new RuntimeException(map.get("return_msg"));
        }
    }


    /**
     * 支付宝支付
     *
     * @param type
     * @param orderId
     * @param httpResponse
     * @return
     */
    @SneakyThrows
    @Override
    public String zfbPay(Integer type, Long orderId, HttpServletResponse httpResponse) {
        // 1. 获取订单信息
        OrderDetail orderDetail = orderMapper.selectOrderDetailById(orderId);
        // 2.创建Client 通过SDK提供的Client对象，负责调用支付宝API
        AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
                aliPayConfig.getMerchantPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
        // 3.创建Request对象
        AlipayTradePagePayRequest request = getAlipayTradePagePayRequest(orderId, orderDetail);
        String body = alipayClient.pageExecute(request).getBody();
        log.info("支付宝支付返回的结果：{}", body);
        // 4.将支付宝的支付结果返回给前端，让前端跳转到支付宝的支付页面
        return body;
    }


    /**
     * 获取支付宝支付请求对象 抽取方法
     *
     * @param orderId
     * @param orderDetail
     * @return
     */
    private AlipayTradePagePayRequest getAlipayTradePagePayRequest(Long orderId, OrderDetail orderDetail) {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());
        request.setReturnUrl(aliPayConfig.getReturnUrl());
        request.setBizContent(" {\"out_trade_no\":\"" + orderId + "\","
                + "\"total_amount\":\"" + orderDetail.getPrice() / 100 + "\","
                + "\"subject\":\"" + orderDetail.getName()
                + "\","
                + "\"body\":\"" + "111111111" + "\","
                +
                "\"timeout_express\":\"" + "30m" + "\","
                +
                "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        return request;
    }

    /**
     * 支付宝支付回调
     */
    @SneakyThrows
    @Override
    public String payNotify(HttpServletRequest request) {
        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                params.put(name, request.getParameter(name));
            }
            // 商户订单号
            String tradeNo = params.get("out_trade_no");
            // 订单支付时间
            String gmtPayment = params.get("gmt_payment");
            // String转Date
            Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(gmtPayment);
            // 更新订单已支付的逻辑代码
            // 更新订单状态
            Order order = orderMapper.selectById(Long.valueOf(tradeNo));
            order.setStatus(2); //已付款
            order.setPayTime(date);//支付时间
            orderMapper.updateById(order);
            // 更新订单支付时间
            // 支付宝验签
            if (Factory.Payment.Common().verifyNotify(params)) {
                // 验签通过
                System.out.println("交易名称: " + params.get("subject"));
                System.out.println("交易状态: " + params.get("trade_status"));
                System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
                System.out.println("商户订单号: " + params.get("out_trade_no"));
                System.out.println("交易金额: " + params.get("total_amount"));
                System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
                System.out.println("买家付款时间: " + params.get("gmt_payment"));
                System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));
            }
        }
        return "success";
    }

    /**
     * 微信支付回调
     */
    @SneakyThrows
    @Override
    public Map<String, String> wxPayNotify(InputStream inputStream) {
        String xml = WXPayUtil.convertToString(inputStream);
        Map<String, String> result = new HashMap<>();
        //解析
        Map<String, String> map = WXPayUtil.xmlToMap(xml);        //验签

        boolean signatureValid = WXPayUtil.isSignatureValid(map);

        if (signatureValid) {
            if ("SUCCESS".equals(map.get("result_code"))) {
                result.put("return_code", "SUCCESS");//成功
                result.put("return_msg", "OK");//订单号
                String out_trade_no = map.get("out_trade_no");
                Order order = orderMapper.selectById(out_trade_no);
                order.setStatus(2); //已付款
                order.setPayTime(new Date());
                orderMapper.updateById(order);
                return result;
            } else {
                log.info("支付回调出错:" + xml);
                result.put("return_code", "FAIL");//失败
                return result;
            }
        } else {
            log.info("支付回调验签失败:" + xml);
            result.put("return_code", "FAIL");//失败
            return result;
        }
    }
}

